﻿using JWTWebApi.Models;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace JWTWebApi.Utils
{
    public class JwtHelper
    {

        /// <summary>
        /// 颁发JWT字符串
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <returns></returns>
        public static string IssueJwt(JwtTokenModel tokenModel)
        {
            string issuer = AppSettings.GetConfig<string>("Jwt:Issuer");
            string audience = AppSettings.GetConfig<string>("Jwt:Audience");
            string secretKey = AppSettings.GetConfig<string>("Jwt:SecretKey");
            double minutes = AppSettings.GetConfig<double>("Jwt:ExpireMinutes");

            List<Claim> claims = new List<Claim>
            {
                // 特别重要：
                // 1、这里将用户的部分信息，比如 uid 存到了Claim 中，如果你想知道如何在其他地方将这个 uid 从 Token 中取出来，请看下边的SerializeJwt() 方法，或者在整个解决方案，搜索这个方法，看哪里使用了！
                // 2、你也可以研究下 HttpContext.User.Claims ，具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
                new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
                new Claim(ClaimTypes.Name, tokenModel.UserName ?? string.Empty), // 添加用户名到Claims
                new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"), // 签发时间
                new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") , // 生效时间
                // 这个就是过期时间，目前是过期5分钟，可自定义，注意JWT有自己的缓冲过期时间
                new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(minutes)).ToUnixTimeSeconds()}"),  // 过期时间戳
                new Claim(ClaimTypes.Expiration, DateTime.Now.AddMinutes(5).ToString()), // .NET框架标准过期时间声明
                new Claim(JwtRegisteredClaimNames.Iss,issuer),
                new Claim(JwtRegisteredClaimNames.Aud,audience),
            };

            // 可以将一个用户的多个角色全部赋予；
            claims.AddRange(tokenModel.Role.Split(',').Select(selector => new Claim(ClaimTypes.Role, selector)));

            // 秘钥 (SymmetricSecurityKey 对安全性的要求，密钥的长度太短会报出异常)
            SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
            // 签名证书
            SigningCredentials credential = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            JwtSecurityToken jwt = new JwtSecurityToken(issuer, audience, claims, null, null, credential);

            JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler();
            string encodedJwt = jwtHandler.WriteToken(jwt);

            return encodedJwt;
        }

        /// <summary>
        /// 解析JWT字符串
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static JwtTokenModel SerializeJwt(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtTokenModel tokenModel = new JwtTokenModel();

            if (!String.IsNullOrEmpty(jwtStr) && jwtHandler.CanReadToken(jwtStr))
            {
                JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
                object role;
                object userName;
                jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
                jwtToken.Payload.TryGetValue(ClaimTypes.Name, out userName); // 提取用户名

                tokenModel = new JwtTokenModel
                {
                    Uid = Convert.ToInt32(jwtToken.Id),
                    UserName = userName?.ToString() ?? string.Empty, // 设置用户名
                    Role = role?.ToString() ?? string.Empty
                };
            }
            return tokenModel;
        }

        /// <summary>
        /// 授权解析jwt
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public static JwtTokenModel ParsingJwtToken(HttpContext httpContext)
        {
            if (!httpContext.Request.Headers.ContainsKey("Authorization"))
            {
                return null;
            }
            string tokenHeader = httpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
            JwtTokenModel model = SerializeJwt(tokenHeader);
            return model;
        }
    }
}
